<?php
//-------------------------------------------------------------------------
// OVIDENTIA http://www.ovidentia.org
// Ovidentia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//-------------------------------------------------------------------------
/**
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
 * @copyright Copyright (c) 2006 by CANTICO ({@link http://www.cantico.fr})
 */

require_once dirname(__FILE__) . '/tableview.class.php';



/**
 * @param string $field
 * @param string $description
 * @param string $attributes
 *
 * @return widget_TableModelViewColumn
 */
function widget_TableModelViewColumn($field, $description)
{
	return new widget_TableModelViewColumn($field, $description);
}



/**
 * A class used to define the content and the properties of a
 * TableModelView column.
 */
class widget_TableModelViewColumn
{
	private $field;
	private $fieldPath;
	private	$description;

	private $visible = true;
	private $sortable = true;
	private $exportable = true;

	private $classes = array();

	public function __construct($field, $description)
	{
		if ($field instanceof ORM_Field) {
			$this->field = $field;
			$this->fieldPath = $field->getPath();
		} else {
			$this->field = null;
			$this->fieldPath = $field;
		}

		$this->description = $description;


	}


	/**
	 * @return ORM_Field
	 */
	public function getField()
	{
		return $this->field;
	}

	/**
	 * @return string
	 */
	public function getFieldPath()
	{
		return $this->fieldPath;
	}


	/**
	 * @return string
	 */
	public function getDescription()
	{
		return $this->description;
	}


	/**
	 * @param bool $visible
	 * @return widget_TableModelViewColumn
	 */
	public function setVisible($visible = true)
	{
		$this->visible = $visible;
		return $this;
	}


	/**
	 * @return bool
	 */
	public function isVisible()
	{
		return $this->visible;
	}


	/**
	 * @param bool $sortable
	 * @return widget_TableModelViewColumn
	 */
	public function setSortable($sortable = true)
	{
		$this->sortable = $sortable;
		return $this;
	}


	/**
	 * @return bool
	 */
	public function isSortable()
	{
		return $this->sortable;
	}


	/**
	 * @param bool $sortable
	 * @return widget_TableModelViewColumn
	 */
	public function setExportable($exportable = true)
	{
		$this->exportable = $exportable;
		return $this;
	}


	/**
	 * @return bool
	 */
	public function isExportable()
	{
		return $this->exportable;
	}


	/**
	 * Adds a css class to the column.
	 *
	 * @param string $className
	 *
	 * @return widget_TableModelViewColumn
	 */
	public function addClass($className)
	{
		$this->classes[$className] = $className;
		return $this;
	}


	/**
	 * Returns an array of css classes associated to the column.
	 * @return array
	 */
	public function getClasses()
	{
		return $this->classes;
	}
}




class widget_TableModelView extends Widget_TableView
{
	/**
	 * @var ORM_Iterator	The data source.
	 */
	protected $iterator;

	/**
	 * @var int				The current page.
	 */
	private $currentPage;

	/**
	 * @var int				The maximum number of rows displayed on the page.
	 */
	private $pageLength = null;


	/**
	 *
	 * @var string
	 */
	private $anchorname;


	protected $allowColumnSelection = false;

	/**
	 * @var array			Information about columns
	 */
	protected $columns = array();
	protected $visibleColumns = array();
	public $columnsDescriptions = array();

	public $sortBaseUrl = null;
	public $sortParameterName = null;


	protected $sortAscending = null;
	protected $sortField = null;



	/**
	 * Defines if the user will be allowed to select visible columns.
	 *
	 * @param bool $allow
	 * @return widget_TableModelView
	 */
	public function allowColumnSelection($allow = true)
	{
		$this->allowColumnSelection = $allow;
		return $this;
	}

	/**
	 * @return bool
	 */
	public function isColumnSelectionAllowed()
	{
		return $this->allowColumnSelection;
	}



	/**
	 * Sets the data source.
	 *
	 * @param ORM_Iterator $iterator
	 * @return widget_TableModelView
	 */
	public function setDataSource(ORM_Iterator $iterator)
	{
		$this->iterator = $iterator;
		return $this;
	}




	/**
	 *
	 * @return string
	 */
	public function exportCsv()
	{
		if (!isset($this->iterator) || empty($this->columns)) {
			return '';
		}

		$set = $this->iterator->getSet();

		$this->initColumns($set);
		$csv = '';

		$nbColumns = count($this->columns);
		$line = array();
		foreach ($this->columns as $columnPath => $column) {
			/* @var $column widget_TableModelViewColumn */
			if (!$column->isExportable()) {
				continue;
			}
			if (!isset($this->columnsDescriptions[$columnPath])) {
				$this->columnsDescriptions[$columnPath] = (string) $column;
			}
			$text = $this->columnsDescriptions[$columnPath];
			$line[] = '"' . str_replace(array('"'), array('""'), $text) . '"';
		}

		$csv .= implode(';', $line) . "\n";

		$this->iterator->seek(0);
		while ($this->iterator->valid()) {
			$record = $this->iterator->current();
			$this->iterator->next();

			$line = array();
			foreach ($this->columns as $fieldPath => $column) {
				/* @var $column widget_TableModelViewColumn */
				if (!$column->isExportable()) {
					continue;
				}
				$text = $this->computeCellTextContent($record, $fieldPath);
				$line[] = '"' . str_replace(array('"'), array('""'), $text) . '"';
			}

			$csv .= implode(';', $line) . "\n";
		}

		return $csv;
	}




	/**
	 * Sets the maximum number of rows that shall be displayed at once.
	 *
	 * @param int $pageLength		or null to unset the limit.
	 * @return widget_TableModelView
	 */
	public function setPageLength($pageLength = null)
	{
		$this->pageLength = $pageLength;
		return $this;
	}

	/**
	 * Returns the maximum number of rows that shall be displayed at once.
	 *
	 * @return int		The maximum number of rows displayed or null if no limit.
	 */
	public function getPageLength()
	{
		return $this->pageLength;
	}


	/**
	 * Sets the currently displayed page. DIsplayed data depends on pageLength.
	 *
	 * @param $pageNumber		First page is 0.
	 * @return widget_TableModelView
	 */
	public function setCurrentPage($pageNumber)
	{
		$this->currentPage = $pageNumber;
		return $this;
	}


	/**
	 * Returns the currently displayed page.
	 *
	 * @return int		The currently displayed page. First page is 0.
	 */
	public function getCurrentPage()
	{
		return $this->currentPage;
	}


	/**
	 * Defines the data source field that will be used to perform sorting.
	 *
	 * @param string $fieldPathAndOrder
	 * @return widget_TableModelView
	 */
	public function setSortField($fieldPathAndOrder)
	{
		list($fieldPath, $order) = explode(':', $fieldPathAndOrder . ':');
		$this->sortAscending = ($order !== 'down');
		$this->sortField = $fieldPath;
		return $this;
	}


	/**
	 * Defines if grouping should be performed.
	 *
	 * @param bool	$doGrouping
	 * @return widget_TableModelView
	 */
	public function setGrouping($doGrouping)
	{
		$this->doGrouping = $doGrouping;
		return $this;
	}




	/**
	 * @param array		$columns
	 * @return widget_TableModelView
	 *
	 * @deprecated by setAvailableColumns
	 * @see widget_TableModelView::setAvailableColumns
	 */
	public function setVisibleColumns(array $columns, $recordSet = null)
	{
		if (!isset($recordSet)) {
			$recordSet = $this->iterator->getSet();
		}
		foreach ($columns as $path => $columnLabel) {
			if ($field = self::getRecordSetField($recordSet, $path)) {
				$col = widget_TableModelViewColumn($field, $columnLabel);
			} else {
				$col = widget_TableModelViewColumn($path, $columnLabel);
			}
			$this->addColumn($col);
		}

		return $this;
	}


	/**
	 *
	 * @return array
	 */
	public function getVisibleColumns()
	{
		if (empty($this->columnsDescriptions)) {
			$this->initColumns($this->iterator->getSet());
		}
		return $this->columns;
	}



	/**
	 * Adds a column to the table model view.
	 *
	 * @param widget_TableModelViewColumn $column The column description.
	 * @param int $position                       Unused for the time being.
	 */
	public function addColumn(widget_TableModelViewColumn $column, $position = null)
	{
		$this->columns[$column->getFieldPath()] = $column;
		$classes = $column->getClasses();
		if (!empty($classes)) {
			$className = implode(' ', $classes);
			$this->addColumnClass(count($this->columns) - 1, $className);
		}
		return $this;
	}


	/**
	 * @param array		$columns
	 * @return widget_TableModelView
	 */
	public function setAvailableColumns(array $columns)
	{
		foreach ($columns as $column) {
			$this->addColumn($column);
		}

		return $this;
	}





	/**
	 * @param ORM_RecordSet	$set
	 * @param string		$fieldPath
	 *
	 * @return ORM_Field		or null
	 */
	static protected function getRecordSetField(ORM_RecordSet $set, $fieldPath)
	{
		$fieldPathElements = explode('/', $fieldPath);
		$field = $set;
		foreach ($fieldPathElements as $fieldName) {
			if (!$field->fieldExist($fieldName)) {
				return null;
			}
			$field = $field->$fieldName;
		}
		return $field;
	}



	/**
	 * @param ORM_Record	$record
	 * @param string		$fieldPath
	 *
	 * @return mixed
	 */
	static protected function getRecordFieldValue(ORM_Record $record, $fieldPath)
	{
		$fieldPathElements = explode('/', $fieldPath);
		$value = $record;
		$field = $record->getParentSet();
		foreach ($fieldPathElements as $fieldName) {
			if (!$field->fieldExist($fieldName)) {
				return null;
			}
			$field = $field->$fieldName;
			$value = $value->$fieldName;
		}

		return $field->output($value);
	}


	/**
	 * @param ORM_Record	$record
	 * @param string		$fieldPath
	 *
	 * @return mixed
	 */
	static protected function getRecordFieldWidget(ORM_Record $record, $fieldPath)
	{
		$fieldPathElements = explode('/', $fieldPath);
		$value = $record;
		foreach ($fieldPathElements as $fieldName) {
			$value = $value->$fieldName;
		}
		return $value;
	}


	/**
	 * Creates the key corresponding to an ORM_Field
	 *
	 * @param ORM_Field $field
	 * @return string
	 */
	public static function getFieldPath(ORM_Field $field)
	{
		$fieldPath = $field->getName();
		for ($parentSet = $field->getParentSet(); $parentSet !== null; $parentSet = $parentSet->getParentSet()) {
			if ($parentSet->getName() !== '') {
				$fieldPath = $parentSet->getName() . '/' . $fieldPath;
			}
		}
		return $fieldPath;
	}




	/**
	 * Set default columns from fields
	 * All columns from SET except primary keys and foreign keys
	 *
	 * @param	ORM_RecordSet	$set
	 */
	private function setDefaultColumns(ORM_RecordSet $set)
	{
		$setFields = $set->getFields();

		foreach ($setFields as $setField) {
			if ($setField instanceof ORM_FkField || $setField instanceof ORM_PkField) {
				continue;
			}

			if ($setField instanceof ORM_RecordSet) {
				$this->setDefaultColumns($setField);
			} else {

				$path = $setField->getPath();

				$this->columns[$path] = $setField;
				$this->columnsDescriptions[$path] = $setField->getDescription();
			}
		}
	}



	/**
	 * Column initialisation from recordSet
	 * @param	ORM_RecordSet	$set
	 *
	 */
	protected function initColumns(ORM_RecordSet $recordSet)
	{
		/* @var $W Func_Widgets */
		$W = bab_Functionality::get('Widgets', false);

		$recordSetFields = $recordSet->getFields();

		if (0 === count($this->columns)) {
			// Missing column initialisation, default mode
			$this->setDefaultColumns($recordSet);
			return;
		}

		if ($this->isColumnSelectionAllowed()) {
			// If column selection is allowed, we fetch the visibility state
			// of the columns in the user configuration.
			foreach ($this->columns as $columnPath => $column) {
				$visible = $W->getUserConfiguration($this->getId() . '/columns/' . $columnPath);
				if (isset($visible)) {
					$column->setVisible($visible);
				}
			}
		}

		$i = 0;
		foreach ($this->columns as $path => $column) {

			/* @var $column widget_TableModelViewColumn */
			if (!$column->isVisible()) {
				$this->addColumnClass($i, 'widget-hidden-column');
			}
			$i++;

			$this->columnsDescriptions[$path] = $column->getDescription();
		}

	}


	/**
	 * Called before data rows
	 * @return unknown_type
	 */
	protected function initHeaderRow(ORM_RecordSet $set)
	{
		require_once $GLOBALS['babInstallPath'] . 'utilit/urlincl.php';

		/* @var $W Func_Widgets */
		$W = bab_Functionality::get('Widgets', false);
		$cols = array();


		$this->addSection('header', null, 'widget-table-header');
		$this->setCurrentSection('header');


		$col = 0;
		$nbColumns = count($this->columns);
		foreach ($this->columns as $columnPath => $column) {

			if (!isset($this->columnsDescriptions[$columnPath])) {
				$this->columnsDescriptions[$columnPath] = (string) $column;
			}

			$columnLabel = $this->columnsDescriptions[$columnPath];
			if (isset($this->sortParameterName) && self::getRecordSetField($set, $columnPath)) {
				if (!isset($this->sortBaseUrl)) {
					$this->sortBaseUrl = bab_url::request_gp();
				}

				if ($this->sortField === $columnPath && $this->sortAscending) {
					$direction = ':down';
				} else {
					$direction = ':up';
				}

				$url = bab_url::mod($this->sortBaseUrl, $this->sortParameterName, $columnPath . $direction);
				if ($anchor = $this->getAnchor()) {
					$url .= '#'.urlencode($anchor);
				}
				$columnItem = $W->Link($columnLabel, $url);
			} else {
				$columnItem = $W->Label($columnLabel);
			}

			$this->addItem($columnItem, 0, $col++);
		}

		if ($this->isColumnSelectionAllowed()) {
			$columnSelectionMenu = $W->Menu(null, $W->FlowLayout())
//					->attachTo($this)
					->addClass('icon-left-16 icon-16x16 icon-left widget-tableview-column-menu');

			$columnSelectionMenu->addItem(
				$W->Title(widget_translate('Choose displayed columns'), 6)->colon()
			);
			$col = 0;
			$currentPageAction = Widget_Action::fromRequest();
			foreach ($this->columns as $path => $column) {
				if($column->getDescription() != ''){
					$columnSelectionMenu->addItem(
						$W->Link(
							$W->Icon($column->getDescription(), $column->isVisible() ? Func_Icons::ACTIONS_DIALOG_OK : ''),
							$currentPageAction
						)->addClass('column-toggle')
						->setMetaData('cellIndex', $col)
						->setMetaData('columnName', $path)
					);
				}
				$col++;
			}
			$columnSelectionMenu->addItem(Widget_Menu::Separator());
			$columnSelectionMenu->addItem(
				$W->Link(
					$W->Icon(widget_translate('Reset to default columns'), Func_Icons::ACTIONS_VIEW_REFRESH),
					$currentPageAction
				)->addClass('columns-reset')
			);

			$this->addItem($columnSelectionMenu, 0, $col);
			$this->addColumnClass($col, 'widget-column-minimal-width');
		}

	}

	/**
	 * Called after data rows
	 *
	 * @param	int	$row		Last row number +1
	 *
	 * @return unknown_type
	 */
	protected function initFooterRow($row)
	{
		$this->addSection('footer', null, 'widget-table-footer');
		$this->setCurrentSection('footer');

		// may be used in inherited classes
	}




	/**
	 *
	 * @param ORM_Record	$record
	 * @param string		$fieldPath
	 * @return string		The text of the item that will be placed in the cell
	 */
	protected function computeCellTextContent(ORM_Record $record, $fieldPath)
	{
		$cellTextContent = self::getRecordFieldValue($record, $fieldPath);
		return $cellTextContent;
	}



	/**
	 *
	 * @param ORM_Record	$record
	 * @param string		$fieldPath
	 * @return Widget_Item	The item that will be placed in the cell
	 */
	protected function computeCellContent(ORM_Record $record, $fieldPath)
	{
		$W = bab_Functionality::get('Widgets');

		$cellContent = $W->Label($this->computeCellTextContent($record, $fieldPath));
		return $cellContent;
	}

	/**
	 * Handle cell content, add the cell widget the the tableview
	 *
	 * @param 	ORM_Record	$record			row record
	 * @param 	string		$fieldPath		collumn name as path is recordSet
	 * @param 	int			$row			row number in table
	 * @param 	int			$col			col number in table
	 * @param	string		$name			if name is set, the cell widget will be added with a namedContainer
	 *
	 * @return 	bool		True if a cell was added
	 */
	protected function handleCell(ORM_Record $record, $fieldPath, $row, $col, $name = null, $rowSpan = null, $colSpan = null)
	{
		$cellContent = $this->computeCellContent($record, $fieldPath);

		if (isset($name))
		{
			require_once dirname(__FILE__).'/namedcontainer.class.php';
			$named = new Widget_NamedContainer($name);
			$named->addItem($cellContent);
			$this->addItem($named, $row, $col);
			return true;
		}

		$this->addItem($cellContent, $row, $col, $rowSpan, $colSpan);
		return true;
	}

	/**
	 * @param ORM_Record	$record
	 * @param int			$row
	 * @return bool			True if a row was added
	 */
	protected function handleRow(ORM_Record $record, $row)
	{
		$col = 0;
		$nbColumns = count($this->columns);
		foreach ($this->columns as $fieldPath => $column) {

			if ($this->isColumnSelectionAllowed() && $col === $nbColumns - 1) {
				$colSpan = 2;
			} else {
				$colSpan = null;
			}
			if ($this->handleCell($record, $fieldPath, $row, $col, null, null, $colSpan)) {
				$col++;
			}
		}
		return true;
	}


	/**
	 * Get a form filter
	 * @see Widget_Filter
	 *
	 * @param	string	$id
	 */
	public function getFilterForm($id = null, $layout = null)
	{
		require_once dirname(__FILE__).'/form.class.php';
		require_once dirname(__FILE__).'/flowlayout.class.php';
		require_once dirname(__FILE__).'/submitbutton.class.php';

		if (null === $layout)
		{
			$layout = new Widget_FlowLayout();
			$layout->setVerticalSpacing(1, 'em')->setHorizontalSpacing(1, 'em');
		}


		$form = new Widget_Form($id);
		$form->setReadOnly(true);
		$form->setName('filter');
		$form->setLayout($layout);
		$form->colon();

		$this->handleFilterFields($form);

		$submit = new Widget_SubmitButton();

		$form->addItem($submit->setLabel(widget_translate('Filter')));
		$form->setSelfPageHiddenFields();
		$form->setAnchor($this->getAnchor());

		return $form;
	}


	/**
	 * Add the filter fields to the filter form
	 * @param Widget_Form $form
	 *
	 */
	protected function handleFilterFields(Widget_Form $form)
	{
		$fields = $this->getVisibleColumns();

		foreach ($fields as $fieldName => $column) {
			/*@var $column widget_TableModelViewColumn */
			$field = $column->getField();

			if (! ($field instanceof ORM_Field)) {
				$field = null;
			}

			$label = $this->handleFilterLabelWidget($fieldName, $field);
			$input = $this->handleFilterInputWidget($fieldName, $field);

			if (isset($input) && isset($label)) {

				$input->setName($fieldName);
				$label->setAssociatedWidget($input);

				$form->addItem($this->handleFilterLabel($label, $input));
			}
		}
	}

	/**
	 * Handle label for input field
	 * If the method return null, no filter field is displayed for the field
	 *
	 * @param string	$fieldName
	 * @param ORM_Field $field
	 *
	 * @return Widget_Label
	 */
	protected function handleFilterLabelWidget($fieldName, $field)
	{
		require_once dirname(__FILE__).'/label.class.php';
		if (isset($this->columnsDescriptions[$fieldName])) {
			$description = $this->columnsDescriptions[$fieldName];
		}

		if (empty($description) && null !== $field) {
			$description = $field->getDescription();
		}

		if (empty($description) && null !== $field) {
			$description = $field->getName();
		}

		if (empty($description)) {
			$description = $fieldName;
		}

		return new Widget_Label($description);
	}


	/**
	 * Handle label and input widget merge in one item before adding to the filter form
	 * default is a vertical box layout
	 *
	 * @param Widget_Label 					$label
	 * @param Widget_Displayable_Interface 	$input
	 * @return Widget_Item
	 */
	protected function handleFilterLabel(Widget_Label $label, Widget_Displayable_Interface $input)
	{
		require_once dirname(__FILE__).'/vboxlayout.class.php';

		$layout = new Widget_VBoxLayout();

		$layout->addItem($label)
			->addItem($input);

		return $layout;
	}



	/**
	 * Handle filter field input widget
	 * If the method returns null, no filter field is displayed for the field
	 *
	 * @param	string			$name		table field name
	 * @param 	ORM_Field		$field		ORM field
	 *
	 * @return Widget_InputWidget | null
	 */
	protected function handleFilterInputWidget($name, ORM_Field $field = null) {

		if (null === $field) {
			return null;
		}

		$W = bab_functionality::get('Widgets');

		if ($field instanceof ORM_DateField) {
			return $W->PeriodPicker();

		} else if ($field instanceof ORM_TimeField) {
			return $W->TimePicker();

		} else if ($field instanceof ORM_StringField) {
			return $W->LineEdit()->setSize(min(array(20, $field->getMaxLength())));

		} else if ($field instanceof ORM_EnumField) {
			$widget = $W->Select();
			$widget->addOption('', '');
			foreach ($field->getValues() as $key => $text) {
				$widget->addOption($key, $text);
			}

			return $widget;

		} else if ($field instanceof ORM_FkField) {
			$widget = $W->Select();
			$widget->addOption('', '');
			$set = $field->newSet();
			$values = $set->select();
			foreach ($values as $record) {
				$widget->addOption($record->id, $record->name);
			}

			return $widget;

		} else if ($field instanceof ORM_RecordSet) {
			$widget = $W->Select();
			$widget->addOption('', '');
			$values = $field->select();
			foreach ($values as $record) {
				$widget->addOption($record->id, $record->name);
			}

			return $widget;

		} else if ($field instanceof ORM_IntField) {
			return $W->LineEdit()->setSize(9);

		} else if ($field instanceof ORM_TextField) {
			return $W->LineEdit()->setSize(20);

		}

		return null;
	}






	/**
	 * Fills the table view with data from the data source.
	 */
	protected function init()
	{
		$iterator = $this->iterator;

		$W = bab_Functionality::get('Widgets', false);

		$set = $iterator->getSet();

		if (isset($this->sortField)) {
			$i = 0;
			foreach ($this->columns as $colPath => $col) {
				if ($this->sortField === $colPath) {
					break;
				}
				$i++;
			}

			if ($sortField = self::getRecordSetField($set, $this->sortField)) {
				if ($this->sortAscending) {
					$this->addColumnClass($i, 'widget-table-column-sorted-asc');
					$iterator->orderAsc($sortField);
				} else {
					$this->addColumnClass($i, 'widget-table-column-sorted-desc');
					$iterator->orderDesc($sortField);
				}
			}
		}
		$this->initColumns($set);
		$this->initHeaderRow($set);


		$this->addSection('body', null, 'widget-table-body');
		$this->setCurrentSection('body');

		$startRow = isset($this->pageLength) ? $this->currentPage * $this->pageLength : 0;
		$iterator->seek($startRow);

		$row = 0;

		$currentGroupValue = null;

		while ($iterator->valid() && (!isset($this->pageLength) || $row < $this->pageLength)) {
		    $record = $iterator->current();
			if (isset($this->doGrouping) && isset($this->sortField)) {
				$newGroupValue = self::getRecordFieldValue($record, $this->sortField);
				if ($newGroupValue !== $currentGroupValue) {
					$this->addSection($newGroupValue, $newGroupValue);
					$this->setCurrentSection($newGroupValue);
					$currentGroupValue = $newGroupValue;
				}
			}
		    $iterator->next();
			if ($this->handleRow($record, $row)) {
				$row++;
			}
		}

		$this->initFooterRow($row);
	}



	/**
	 * Set an anchor for destination page
	 * @param string $anchorname
	 * @return Widget_PageSelector
	 */
	public function setAnchor($anchorname)
	{
		$this->anchorname = $anchorname;
		return $this;
	}


	/**
	 * Get the anchor name of destination page
	 * @return string | null
	 */
	public function getAnchor()
	{
		return $this->anchorname;
	}



	/**
	 * Get multi-page selector widget
	 *
	 *
	 * @return Widget_Item | null
	 */
	protected function handlePageSelector()
	{
		require_once dirname(__FILE__).'/pageselector.class.php';

		$selector = new Widget_PageSelector;
		$selector->setPageLength($this->getPageLength());
		$selector->setIterator($this->iterator);
		$selector->setCurrentPage($this->getCurrentPage());
		if (isset($this->sortField)) {
			$selector->setSortField($this->sortField);
		}

		$namePath = $this->getNamepath();
		$namePath[] = 'filter';
		$namePath[] = 'pageNumber';

		$selector->setPageNamePath($namePath);
		$selector->setAnchor($this->getAnchor());

		if ($selector->getNbPages() > 1) {
			return $selector;
		}

		return null;
	}




	/**
	 * (non-PHPdoc)
	 * @see programs/widgets/Widget_TableView#display($canvas)
	 * @todo make a variable of ['filter']['pageNumber']
	 */
	public function display(Widget_Canvas $canvas)
	{
		$this->init();

		$list = parent::display($canvas);

		$selector = $this->handlePageSelector();

		if (null !== $selector) {
			return $canvas->vbox(null, array('widget-filter-bottom'), array($list, $selector->display($canvas)));
		}

		return $list;
	}

}
